<html>
<body>
<h1 id="cf-simpledb">cf-simpledb</h1>

<p>A high-level (boto-style) framework and a Custom Tag to access AWS SimpleDB Cloud Database from within Railo. Based on official AWS Java SDK.</p>

<p>To understand cf-simpledb calls better, you be familiar with the SimpleDB concepts and consult the <a href="http://docs.amazonwebservices.com/AWSJavaSDK/latest/javadoc/index.html">AWS SDK docs</a>.</p>

<h2 id="knownissues">Known issues</h2>

<ul>
<li>Does not run on ColdFusion yet, since I develop only on Railo and CF lacks real CFSCRIPT support and tight Java integration. Please feel free to contribute for better ColdFusion compatibility!</li>
</ul>

<h2 id="installation">Installation</h2>

<ol>
<li>Download the most current <a href="http://aws.amazon.com/sdkforjava/">AWS SDK for Java</a> JARs and put them into your [webroot]/WEB-INF/railo/lib/ directory</li>
<li>To make the AWS SDK work, you may also need to download the <a href="http://hc.apache.org/downloads.cgi">Apache HttpClient</a> JARs and put them in the same directory</li>
<li>Drop the &#8220;sdb&#8221; folder into your webroot or components-directory</li>
<li>Drop &#8220;sdbquery.cfm&#8221; into your Custom Tags folder</li>
</ol>

<h3 id="listofjarsinyourlib-directory">List of JARs in your lib-directory</h3>

<pre><code>aws-java-sdk-1.3.8-javadoc.jar
aws-java-sdk-1.3.8-sources.jar
aws-java-sdk-1.3.8.jar
aws-java-sdk-flow-build-tools-1.3.8.jar
commons-codec-1.4.jar
commons-logging-1.1.1.jar
httpclient-4.1.3.jar
httpclient-cache-4.1.3.jar
httpcore-4.1.4.jar
httpmime-4.1.3.jar
jackson-all-1.9.7.jar
</code></pre>

<h2 id="usage">Usage</h2>

<h3 id="cf_sdbquery">&lt;CF_SDBQUERY&gt;</h3>

<p>If you like to access data the <CFQUERY>-style, the package provides a neat like Custom Tag to allow you to fetch data from SimpleDB and get a real ColdFusion query back! It even cares about fix column names etc. Just put the &#8220;sdbquery.cfm&#8221; in your Custom Tag directory and call it this way:</p>

<pre><code>&lt;cf_sdbquery datasource=&quot;connection&quot; name=&quot;data&quot;&gt;
    SELECT * FROM warehouse
&lt;/cf_sdbquery&gt;
</code></pre>

<p><em>Returns a native SQL query object!</em>
If you specify a column list, like</p>

<pre><code>&lt;cf_sdbquery datasource=&quot;connection&quot; name=&quot;data&quot;&gt;
    SELECT order_id, firstname, lastname FROM warehouse
&lt;/cf_sdbquery&gt;
</code></pre>

<p>instead, your result set will return the columns even if the key did not appear on any item in your results. This way you can securely loop over the query without hitting an undefined key.</p>

<table>
<caption id="cf_sdbqueryattributes">&lt;CF_SDBQUERY&gt; attributes</caption>
<colgroup>
<col style="text-align:left;"/>
<col style="text-align:center;"/>
<col style="text-align:left;"/>
</colgroup>

<thead>
<tr>
	<th style="text-align:left;">Attribute</th>
	<th style="text-align:center;"></th>
	<th style="text-align:left;">Usage</th>
</tr>
</thead>

<tbody>
<tr>
	<td style="text-align:left;"> datasource</td>
	<td style="text-align:center;"><em>required</em></td>
	<td style="text-align:left;">The name of the variable where you have initialized the SDB connection (Access.cfc), see <em>API Usage</em></td>
</tr>
<tr>
	<td style="text-align:left;"> name</td>
	<td style="text-align:center;"><em>required</em></td>
	<td style="text-align:left;">Name of variable for query data (see CF docs)</td>
</tr>
<tr>
	<td style="text-align:left;"> result</td>
	<td style="text-align:center;"> </td>
	<td style="text-align:left;">Name of variable to store metadata about the query including some SimpleDB specific information </td>
</tr>
<tr>
	<td style="text-align:left;"> maxrows</td>
	<td style="text-align:center;"> </td>
	<td style="text-align:left;"> Since SimpleDB does only return a maximum of 2500 items or less (depending on size) per query, you can specify maxrows to fetch from SimpleDB until MAXROWS is reached or there are no more items </td>
</tr>
</tbody>
</table>
<h3 id="high-levelapi">High-Level API</h3>

<p>For advanced operations (write, update, domain management, etc.) you must use the high-level API. The API provides you also with a very convenient Item-Class with magic getters and setters, so you can use it like the ColdFusion ORM, just must easier!</p>

<table>
<caption id="access.cfc">Access.cfc</caption>
<colgroup>
<col style="text-align:right;"/>
<col style="text-align:left;"/>
<col style="text-align:left;"/>
</colgroup>

<thead>
<tr>
	<th style="text-align:right;">Returns</th>
	<th style="text-align:left;">Function(parameters)</th>
	<th style="text-align:left;"></th>
</tr>
</thead>

<tbody>
<tr>
	<td style="text-align:right;"></td>
	<td style="text-align:left;" colspan="2"><em>Instantiate to get a connection to Amazon SimpleDB. Use domain()-factory functions to get access to a domains and its items</em></td>
</tr>
<tr>
	<td style="text-align:right;">self</td>
	<td style="text-align:left;">init(accessKey, secretKey)</td>
	<td style="text-align:left;"></td>
</tr>
<tr>
	<td style="text-align:right;">self</td>
	<td style="text-align:left;">withEndpoint(endpoint)</td>
	<td style="text-align:left;">change default endpoint</td>
</tr>
<tr>
	<td style="text-align:right;">Domain</td>
	<td style="text-align:left;">domain(domainName)</td>
	<td style="text-align:left;"></td>
</tr>
<tr>
	<td style="text-align:right;">[str]</td>
	<td style="text-align:left;">listDomains()</td>
	<td style="text-align:left;"></td>
</tr>
</tbody>
</table>


<table>
<caption id="domain.cfc">Domain.cfc</caption>
<colgroup>
<col style="text-align:right;"/>
<col style="text-align:left;"/>
<col style="text-align:left;"/>
</colgroup>

<thead>
<tr>
	<th style="text-align:right;">Returns</th>
	<th style="text-align:left;">Function(parameters)</th>
	<th style="text-align:left;"></th>
</tr>
</thead>

<tbody>
<tr>
	<td style="text-align:right;"></td>
	<td style="text-align:left;" colspan="2"><em>Represents a domain</em></td>
</tr>
<tr>
	<td style="text-align:right;">self</td>
	<td style="text-align:left;">init(access, domainName)</td>
	<td style="text-align:left;">Only needed if you do not use Access.domain() factory</td>
</tr>
<tr>
	<td style="text-align:right;">bool</td>
	<td style="text-align:left;">exists()</td>
	<td style="text-align:left;"></td>
</tr>
<tr>
	<td style="text-align:right;">int</td>
	<td style="text-align:left;">itemCount()</td>
	<td style="text-align:left;"></td>
</tr>
<tr>
	<td style="text-align:right;">void</td>
	<td style="text-align:left;">create()</td>
	<td style="text-align:left;"></td>
</tr>
<tr>
	<td style="text-align:right;">void</td>
	<td style="text-align:left;">delete(force=false)</td>
	<td style="text-align:left;">if <em>true</em>, domain will be deleted with items</td>
</tr>
<tr>
	<td style="text-align:right;">obj</td>
	<td style="text-align:left;">metadata()</td>
	<td style="text-align:left;">get access to SimpleDB low-level metadata functions, see SDK docs</td>
</tr>
<tr>
	<td style="text-align:right;">item</td>
	<td style="text-align:left;">item(itemName)</td>
	<td style="text-align:left;">return a CachedItem.cfc with <em>itemName</em></td>
</tr>
<tr>
	<td style="text-align:right;">Select</td>
	<td style="text-align:left;">select()</td>
	<td style="text-align:left;">return a pre-set select object (see below)</td>
</tr>
<tr>
	<td style="text-align:right;">void</td>
	<td style="text-align:left;">serializeToFile(path, overwrite=false)</td>
	<td style="text-align:left;">export complete domain data to JSON file</td>
</tr>
</tbody>
</table>


<table>
<caption id="item.cfc">Item.cfc</caption>
<colgroup>
<col style="text-align:right;"/>
<col style="text-align:left;"/>
<col style="text-align:left;"/>
</colgroup>

<thead>
<tr>
	<th style="text-align:right;">Returns</th>
	<th style="text-align:left;">Function(parameters)</th>
	<th style="text-align:left;"></th>
</tr>
</thead>

<tbody>
<tr>
	<td style="text-align:right;"></td>
	<td style="text-align:left;" colspan="2"><em>A low-level SimpleDB item. Every operation on Item.cfc will be executed directly. Use CachedItem.cfc for full functionality</em></td>
</tr>
<tr>
	<td style="text-align:right;">self</td>
	<td style="text-align:left;" colspan="2">init(access, domain, itemName)</td>
</tr>
<tr>
	<td style="text-align:right;">self</td>
	<td style="text-align:left;" colspan="2">init(access, domain, itemName)</td>
</tr>
<tr>
	<td style="text-align:right;">str</td>
	<td style="text-align:left;" colspan="2">getItemName()</td>
</tr>
<tr>
	<td style="text-align:right;">[str]</td>
	<td style="text-align:left;">get(key)</td>
	<td style="text-align:left;">return value of key, either string or array of strings if key appears multiple times</td>
</tr>
<tr>
	<td style="text-align:right;">[str]</td>
	<td style="text-align:left;">get<em>Key</em>()</td>
	<td style="text-align:left;">magic getter, key will be lowercased</td>
</tr>
<tr>
	<td style="text-align:right;">void</td>
	<td style="text-align:left;">set(key, value)</td>
	<td style="text-align:left;">value must be either a string or array of strings</td>
</tr>
<tr>
	<td style="text-align:right;">void</td>
	<td style="text-align:left;">set<em>Key</em>()</td>
	<td style="text-align:left;">magic setter, key will be lowercased</td>
</tr>
<tr>
	<td style="text-align:right;">bool</td>
	<td style="text-align:left;" colspan="2">has(key)</td>
</tr>
<tr>
	<td style="text-align:right;">bool</td>
	<td style="text-align:left;">has<em>Key</em>()</td>
	<td style="text-align:left;">magic &#8230; <em>has</em>er? :-)</td>
</tr>
<tr>
	<td style="text-align:right;">void</td>
	<td style="text-align:left;" colspan="2">remove(key)</td>
</tr>
<tr>
	<td style="text-align:right;">void</td>
	<td style="text-align:left;" colspan="2">delete()</td>
</tr>
<tr>
	<td style="text-align:right;">bool</td>
	<td style="text-align:left;" colspan="2">exists()</td>
</tr>
<tr>
	<td style="text-align:right;">struct</td>
	<td style="text-align:left;" colspan="2">fetch(consistent=false)</td>
</tr>
<tr>
	<td style="text-align:right;">struct</td>
	<td style="text-align:left;" colspan="2">toMemento()</td>
</tr>
</tbody>
</table>


<table>
<caption id="cacheditem.cfc">CachedItem.cfc</caption>
<colgroup>
<col style="text-align:right;"/>
<col style="text-align:left;"/>
<col style="text-align:left;"/>
</colgroup>

<thead>
<tr>
	<th style="text-align:right;">Returns</th>
	<th style="text-align:left;">Function(parameters)</th>
	<th style="text-align:left;"></th>
</tr>
</thead>

<tbody>
<tr>
	<td style="text-align:right;"></td>
	<td style="text-align:left;" colspan="2"><em>Adds cache to item, reduced roundtrips. You need to call save() or refresh() manually. Adds cache info to toMemento() result. Inherits all from Item and adds:</em></td>
</tr>
<tr>
	<td style="text-align:right;">void</td>
	<td style="text-align:left;">save()</td>
	<td style="text-align:left;">Save any changes made to object</td>
</tr>
<tr>
	<td style="text-align:right;">void</td>
	<td style="text-align:left;">refresh()</td>
	<td style="text-align:left;">Re-fetch object from SimpleDB</td>
</tr>
</tbody>
</table>


<table>
<caption id="select.cfc">Select.cfc</caption>
<colgroup>
<col style="text-align:right;"/>
<col style="text-align:left;"/>
<col style="text-align:left;"/>
</colgroup>

<thead>
<tr>
	<th style="text-align:right;">Returns</th>
	<th style="text-align:left;">Function(parameters)</th>
	<th style="text-align:left;"></th>
</tr>
</thead>

<tbody>
<tr>
	<td style="text-align:right;"></td>
	<td style="text-align:left;" colspan="2"><em>Select items using SQL. Create it using Domain.select()</em></td>
</tr>
<tr>
	<td style="text-align:right;">self</td>
	<td style="text-align:left;" colspan="2">init(access)</td>
</tr>
<tr>
	<td style="text-align:right;">self</td>
	<td style="text-align:left;">domain(domainName)</td>
	<td style="text-align:left;">Set Domain name of SQL Query</td>
</tr>
<tr>
	<td style="text-align:right;">self</td>
	<td style="text-align:left;">keys(keyList=&#8220;*&#8221;)</td>
	<td style="text-align:left;">Set Column part of SQL Query</td>
</tr>
<tr>
	<td style="text-align:right;">self</td>
	<td style="text-align:left;">where(whereClause)</td>
	<td style="text-align:left;">Set WHERE part of SQL Query</td>
</tr>
<tr>
	<td style="text-align:right;">self</td>
	<td style="text-align:left;">orderby(orderClause)</td>
	<td style="text-align:left;">Set WHERE part of SQL Query</td>
</tr>
<tr>
	<td style="text-align:right;">self</td>
	<td style="text-align:left;">limit(num=100)</td>
	<td style="text-align:left;">Return max. records per Request</td>
</tr>
<tr>
	<td style="text-align:right;">string</td>
	<td style="text-align:left;">toSql()</td>
	<td style="text-align:left;">Return constructed SQL query (for diagnose)</td>
</tr>
<tr>
	<td style="text-align:right;">[CachedItems]</td>
	<td style="text-align:left;">execute(<em>sqlString</em>)</td>
	<td style="text-align:left;">Return array of CachedItems. Use <em>sqlString</em> to pass SQL manually instead of using functions above</td>
</tr>
<tr>
	<td style="text-align:right;">bool</td>
	<td style="text-align:left;">hasMore()</td>
	<td style="text-align:left;">True, if there are more Items. Call execute() until hasMore() is false</td>
</tr>
</tbody>
</table>
<h2 id="versionhistory">Version History</h2>

<h3 id="">1.1 (2012&#8211;05&#8211;19)</h3>

<ul>
<li>Added CF_SDBQUERY Custom Tag for convenience</li>
<li>Fixed bug in Select.cfc where multiple execute() calls did return the same data instead of more data</li>
</ul>

<h2 id="contact">Contact</h2>

<p>If you want to contribute or give feedback, please drop me a note &lt;louis.brauer@pixeltex.com&gt;, visit <a href="http://pxl.gg">http://pxl.gg</a> or follow <a href="http://twitter.com/louisbrauer">http://twitter.com/louisbrauer</a>.</p>

<h2 id="license">License</h2>

<p>Open Source Initiative OSI
MIT License</p>

<p>Copyright (c) 2012 PIXELTEX (Schweiz) GmbH</p>

<p>Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the &#8220;Software&#8221;), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:</p>

<p>The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</p>

<p>THE SOFTWARE IS PROVIDED &#8220;AS IS&#8221;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</p>
</body>
  </html>